Skip to content

fix(keyboard): forward unbound Cmd+Shift combinations to terminal - #1757

Closed
BillionClaw wants to merge 1 commit into
manaflow-ai:mainfrom
BillionClaw:clawoss/fix/cmd-shift-keys-1773835501
Closed

BillionClaw wants to merge 1 commit into
manaflow-ai:mainfrom
BillionClaw:clawoss/fix/cmd-shift-keys-1773835501

Conversation

@BillionClaw

@BillionClaw BillionClaw commented Mar 18, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #1718

Problem

Unbound Cmd+Shift+\<key\> key combinations were being silently swallowed by the AppKit key-routing layer. They never reached the terminal application via the kitty keyboard protocol.

The root cause was in performKeyEquivalent: the two-pass timestamp mechanism returned false on the first pass, expecting AppKit to redispatch. However, AppKit never redispatches events that don't match any menu item or Ghostty binding.

Solution

Forward unbound Command-modified keys directly to keyDown instead of relying on AppKit's redispatch mechanism. This ensures the kitty keyboard protocol receives the events for applications like Neovim that rely on super modifier keys.

Changes

  • Modified GhosttyTerminalView.swift performKeyEquivalent method
  • Removed the two-pass timestamp mechanism for unbound keys
  • Unbound Cmd+Shift combinations now flow directly to the terminal

Testing

  • Unbound Cmd+Shift+K should now reach the terminal as CSI escape sequence
  • Applications using kitty keyboard protocol (Neovim \u2265 0.10) can now receive \<S-D-J\> / \<S-D-K\> mappings

Summary by cubic

Forward unbound Cmd+Shift key combinations directly to the terminal so they are no longer dropped by AppKit. Fixes missing key events in apps using the kitty keyboard protocol (e.g., Neovim).

  • Bug Fixes
    • Forward unbound Command-modified keys to keyDown in performKeyEquivalent.
    • Remove the two-pass timestamp redispatch logic that AppKit never delivers.
    • Cmd+Shift combos now reach the terminal (e.g., Neovim mappings like /).

Written for commit f0f297a. Summary will update on new commits.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Refined keyboard event handling for command-modified keys to ensure they are correctly processed and routed to the terminal application. Enhanced key translation paths for specific key combinations to provide more predictable and consistent behavior with keyboard shortcuts and input handling.

Unbound Cmd+Shift+<key> combinations were being silently swallowed by
the AppKit key-routing layer. The two-pass timestamp mechanism in
performKeyEquivalent relied on AppKit to redispatch events, but AppKit
never redispatches unbound keys that don't match menu items.

Fix by forwarding unbound Command-modified keys directly to keyDown
instead of returning false and hoping for redispatch. This ensures
the kitty keyboard protocol receives the events.

Fixes manaflow-ai#1718
@vercel

vercel Bot commented Mar 18, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Mar 18, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The fix addresses a bug where unbound Cmd+Shift key combinations were silently consumed by AppKit's menu routing instead of reaching the terminal. The code now explicitly forwards unbound Cmd-modified keys to the terminal via keyDown and adds special handling for specific control characters.

Changes

Cohort / File(s) Summary
Key Event Routing Fix
Sources/GhosttyTerminalView.swift
Modified performKeyEquivalent to forward unbound Cmd-modified keys directly to the terminal instead of falling back to AppKit's default handling. Added explicit keyDown forwarding for certain keys like \r and / with tailored character translation. Removed two-pass timestamp consolidation logic that relied on AppKit redispatching unbound events.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A key slipped through AppKit's domain,
Lost in the routing, again and again.
But now with a hop, we guide it true,
Direct to the terminal—Cmd-Shift shines through! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: forwarding unbound Cmd+Shift key combinations to the terminal instead of letting AppKit drop them.
Description check ✅ Passed The PR description is comprehensive, clearly explaining the problem, root cause, solution, and testing approach. However, it lacks explicit testing evidence (no manual testing checklist items marked) and no demo video is provided.
Linked Issues check ✅ Passed The code changes directly address issue #1718 by forwarding unbound Cmd-modified keys to keyDown instead of relying on AppKit redispatch, allowing the kitty keyboard protocol to receive events.
Out of Scope Changes check ✅ Passed All changes in GhosttyTerminalView.swift are directly scoped to fixing the keyboard event handling for unbound Cmd+Shift combinations, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 4881-4888: The new unbound-Command forwarding path in
GhosttyTerminalView.swift unconditionally clears lastPerformKeyEvent and calls
keyDown(with: event), which incorrectly forwards Cmd+` (keyCode 50) and breaks
AppKit/window-menu routing; update the handler to detect the Command-modified
backtick (check event.keyCode == 50 and event.modifierFlags contains .command)
and skip the forwarding for that combo (leave lastPerformKeyEvent intact and
allow normal AppKit/menu routing), while continuing to forward other unbound
Command keys via lastPerformKeyEvent = nil; keyDown(with: event).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ce0990c-92ac-4823-bef4-1fbca4309d32

📥 Commits

Reviewing files that changed from the base of the PR and between 1311d4a and f0f297a.

📒 Files selected for processing (1)
  • Sources/GhosttyTerminalView.swift

Comment on lines +4881 to +4888
// For unbound Command-modified keys (e.g., Cmd+Shift+K with no binding),
// forward directly to the terminal rather than relying on AppKit's redispatch.
// AppKit may drop the event if no menu item matches, preventing the key from
// reaching the terminal via the kitty keyboard protocol.
// See: https://github.com/manaflow-ai/cmux/issues/1718
lastPerformKeyEvent = nil
keyDown(with: event)
return true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Exclude `Cmd+`` from the new unbound-Command forwarding path.

Line 4881 currently forwards all unbound Command keys to keyDown(with:). That also catches `Cmd+`` (keyCode 50), which should remain on AppKit/window-menu routing for window cycling.

🔧 Proposed fix
-            lastPerformKeyEvent = nil
-            keyDown(with: event)
-            return true
+            // Keep Cmd+` on AppKit/window-menu routing (window cycling).
+            if event.keyCode == 50 {
+                lastPerformKeyEvent = nil
+                return false
+            }
+
+            lastPerformKeyEvent = nil
+            keyDown(with: event)
+            return true

Based on learnings Repo: manaflow-ai/cmux — Command-backtick (Cmd+, keyCode 50) is intentionally excluded from direct menu routing; do not add a bypass for Cmd+.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/GhosttyTerminalView.swift` around lines 4881 - 4888, The new
unbound-Command forwarding path in GhosttyTerminalView.swift unconditionally
clears lastPerformKeyEvent and calls keyDown(with: event), which incorrectly
forwards Cmd+` (keyCode 50) and breaks AppKit/window-menu routing; update the
handler to detect the Command-modified backtick (check event.keyCode == 50 and
event.modifierFlags contains .command) and skip the forwarding for that combo
(leave lastPerformKeyEvent intact and allow normal AppKit/menu routing), while
continuing to forward other unbound Command keys via lastPerformKeyEvent = nil;
keyDown(with: event).

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/GhosttyTerminalView.swift">

<violation number="1" location="Sources/GhosttyTerminalView.swift:4888">
P2: Unbound Command key equivalents are now always consumed in `performKeyEquivalent`, which can block app/menu shortcuts from routing through AppKit.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// See: https://github.com/manaflow-ai/cmux/issues/1718
lastPerformKeyEvent = nil
keyDown(with: event)
return true

@cubic-dev-ai cubic-dev-ai Bot Mar 18, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Unbound Command key equivalents are now always consumed in performKeyEquivalent, which can block app/menu shortcuts from routing through AppKit.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/GhosttyTerminalView.swift, line 4888:

<comment>Unbound Command key equivalents are now always consumed in `performKeyEquivalent`, which can block app/menu shortcuts from routing through AppKit.</comment>

<file context>
@@ -4878,18 +4878,17 @@ class GhosttyNSView: NSView, NSUserInterfaceValidations {
+            // See: https://github.com/manaflow-ai/cmux/issues/1718
+            lastPerformKeyEvent = nil
+            keyDown(with: event)
+            return true
         }
 
</file context>
Fix with Cubic

@CMLKevin

Copy link
Copy Markdown

Closing older duplicate PR; keeping the newest open.

1 similar comment
@CMLKevin

Copy link
Copy Markdown

Closing older duplicate PR; keeping the newest open.

@CMLKevin

Copy link
Copy Markdown

I’ll get the CLA signed — will follow up once it’s done.

@BillionClaw

Copy link
Copy Markdown
Contributor Author

Closing per repository blocklist: maintainer threatened to ban. All submissions to this repo have been suspended.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unbound Cmd+Shift+<key> key combinations are silently swallowed, they never reach terminal/kitty protocol

2 participants